package test;

import expression.Expression;
import expression.ExpressionAn;
import expression.ExpressionDefine;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import tree.Node;
import util.LoadPackageClasses;

import java.io.IOException;
import java.util.*;

/**
 * Hello world!
 *
 * 表达式换算为属性结构，并最后进行计算
 *
 * A+B
 * 做特殊字符的判断 表达式允许的字符 + - * / % ^ A-Z a-z 0-9 $ # " ' . & | _ - 其他都是不可用字符串
 * 34-39
 * 42-57
 * 60-62
 * 65-90
 * 92
 * 94-122
 * 124
 * 范围型字符{} [] ()
 * 123
 * 125
 * 91
 * 93
 * 40-41
 *
 * 形成asc2 int 长数组 长度127
 * 1.代表表达式字符
 * 2.代表范围型字符
 */
public class App {
    //127特殊字符的对照
    private static Integer[] ascArray = new Integer[127];
    //分组字符的对照
    private static Map<Character, Character> contrastCh = new HashMap<Character, Character>();
    //表达式容器
    private static Map<String, Expression> expContainer = new HashMap<String, Expression>();
    //
    private static Map<String, ExpressionDefine> expDefContainer = new HashMap<String, ExpressionDefine>();
    //等级表达式容器
//    private static Map<Integer, Map<String, Expression>> rankExpContainer = new TreeMap<Integer, Map<String, Expression>>();
    //默认所在包路径
    private static String expClassPath = Expression.class.getPackage().getName();
    //
    static {
        //初始化标记长数组
        for(int i = 0; i < ascArray.length; i++) {//正常符号
            if((34 <= i && i <= 39) ||
                    (42 <= i && i <= 43) ||
                    (45 <= i && i <= 57) ||
                    (60 <= i && i <= 62) ||
                    (65 <= i && i <= 90) ||
                    92 == i ||
                    (94 <= i && i <= 122) ||
                    124 == i) {
                ascArray[i] = 1;
            } else if(123 == i || 125 == i ||//括号
                    91 == i || 93 == i ||
                    40 == i || 41 == i) {
                ascArray[i] = 2;
            } else if(44 == i) {//,号
                ascArray[i] = 3;
            } else {
                ascArray[i] = 0;
            }
        }
        //初始化分组字符的对照
        contrastCh.put('(', ')');
        contrastCh.put('{', '}');
        contrastCh.put('[', ']');
    }

    /**
     * 生成表达式容器
     */
    private static void initExpContainer() throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        LoadPackageClasses loadPackageClasses = new LoadPackageClasses(new String[]{expClassPath}, ExpressionAn.class);
        Set<Class<?>> classSet = loadPackageClasses.getClassSet();
        for(Class clazz : classSet) {//从相应的注解获取相应的名称，如果不存在使用类命名规则
            ExpressionAn expAn = (ExpressionAn) clazz.getAnnotation(ExpressionAn.class);
            Expression expression = (Expression) clazz.newInstance();
            String text = expAn.text();
            if(StringUtils.isEmpty(text)) {
                text = clazz.getSimpleName().replaceAll("Expression$", "").toUpperCase();
            }
            expContainer.put(text, expression);
            expDefContainer.put(text, new ExpressionDefine(expAn));
        }
    }

    /**
     *
     * @param expStr
     * @param obj
     * @return
     * @throws Exception
     */
    private static Node genExpTree(String expStr, Object obj) throws Exception {
        Node curNode = new Node();
        List<String> exps = expList(expStr);
        //
        for(String exp : exps) {
            if(StringUtils.startsWith(exp, "(")) {
                Node node = genExpTree(exp.substring(1, exp.length() - 1), obj);
                curNode.addChild(node.getChildren().get(0));
            } else if(expContainer.containsKey(exp) || (exp.indexOf('(') > -1 && expContainer.containsKey(exp.substring(0, exp.indexOf('('))))) {//表达式处理
                String expName = exp;
                String paramExpression = null;
                if(exp.indexOf('(') > -1 && expContainer.containsKey(exp.substring(0, exp.indexOf('(')))) {
                    expName = exp.substring(0, exp.indexOf('('));
                    paramExpression = exp.substring(exp.indexOf('(') + 1, exp.length() - 1);
                }
                while(null != curNode &&
                        null != curNode.getParent() &&
                        null != curNode.getText() &&
                        ((!curNode.getText().equals(curNode.getFullText())) ||
                        (expDefContainer.containsKey(curNode.getFullText()) &&
                        expDefContainer.get(curNode.getText()).getRank() <= expDefContainer.get(expName).getRank()))) {
                    curNode = curNode.getParent();
                }
                Node temp1 = curNode;
                Node temp2;
                curNode = new Node(expName, exp, null, null, expContainer.get(expName));
                if(CollectionUtils.isNotEmpty(temp1.getChildren())) {
                    temp2 = temp1.getChildren().get(temp1.getChildren().size() - 1);
                    temp1.getChildren().remove(temp1.getChildren().size() - 1);
                    curNode.addChild(temp2);
                }
                temp1.addChild(curNode);
                //如果curNode之中含有参数
                if(StringUtils.isNotEmpty(paramExpression)) {
                    List<String> paramList = paramList(paramExpression);
                    for(String param : paramList) {
                        Node node = genExpTree(param, obj);
                        curNode.addChild(node.getChildren().get(0));
                    }
                }
            } else {//value相关表达式处理
                curNode.addChild(new Node(exp, exp, expContainer.get("VALUE").exec(exp, obj), null, null));
            }
        }
        //
        return curNode.getRoot();
    }

    /**
     * 主执行函数
     *
     * @param expStr
     * @param obj
     */
    public static Object exec(String expStr, Object obj) throws Exception {
        //得到树形root，按照层级进行计算
        Node node = genExpTree(expStr, obj);
        //获得结果
        return node.getRes(obj);
    }

    /**
     * 获取参数列表
     * @param exp
     * @return
     */
    private static List<String> paramList(String exp) {
        List<String> result = new LinkedList<String>();
        char[] chars = exp.toCharArray();
        StringBuilder expB = new StringBuilder();
        Stack<Character> stack = new Stack<Character>();
        for(char ch : chars) {
            int mark = ascArray[ch];
            if(3 == mark && stack.empty()) {
                if(expB.length() > 0) {
                    result.add(StringUtils.trim(expB.toString()));
                    expB = new StringBuilder();
                }
                continue;
            }
            expB.append(ch);
            if(2 == mark) {
                if(contrastCh.containsKey(ch)) {//如果是左边的
                    stack.push(ch);
                } else {//如果是右边的
                    stack.pop();
                }
            }
        }
        if(expB.length() > 0) {
            result.add(expB.toString());
        }
        return result;
    }

    /**
     * 获取表达式list
     *
     * @param exp
     * @return
     */
    private static List<String> expList(String exp) {
        List<String> result = new LinkedList<String>();
        char[] chars = exp.toCharArray();
        StringBuilder expB = new StringBuilder();
        Stack<Character> stack = new Stack<Character>();
        for(char ch : chars) {
            int mark = ascArray[ch];
            if(0 == mark && stack.empty()) {
                if(expB.length() > 0) {
                    result.add(StringUtils.trim(expB.toString()));
                    expB = new StringBuilder();
                }
            }
            if(!stack.empty()) {
                expB.append(ch);
            } else if(1 == mark || 2 == mark) {
                expB.append(ch);
            }
            if(2 == mark) {
                if(contrastCh.containsKey(ch)) {//如果是左边的
                    stack.push(ch);
                } else {//如果是右边的
                    stack.pop();
                }
            }
        }
        if(expB.length() > 0) {
            result.add(expB.toString());
        }
        return result;
    }

    /**
     * 下一个优化，也需要进行分解
     * @param args
     */
    public static void main(String[] args) throws Exception {
//        String testExp = "123 ,456, (123 + A(123,23)) + 3";
//        paramList(testExp);
        App.initExpContainer();
        long start = System.currentTimeMillis();
        for(int i = 0; i < 1000000; i++) {
            String testExp = "A(123) + (A(123,134,A(123, 2) + 2) * 3)";
            App.exec(testExp, null);
        }
        long end = System.currentTimeMillis();
        System.err.println(end - start);
        //
//        String testExp = "A(123) + C({123;233;123},D(123,123,123))";
//        App.initExpContainer();
//        String testExp = "1 = 1 & 2 = 2";//结构性变化
//        Assert.isTrue((Boolean) exec(testExp, null));
//        testExp = "'N' ISNUM";//单参数单表达式
//        Assert.isTrue(!(Boolean) exec(testExp, null));
//        testExp = "1";//单value
//        Assert.isTrue(1 == Integer.valueOf(exec(testExp, null).toString()));
//        testExp = "NOW";//单函数
//        System.err.println(exec(testExp, null));
//        System.err.println(JSON.toJSONString(expList(testExp)));
    }
}
